<?php
namespace GFPHP;
use Model\Model;
if (!defined('__ROOT__')) exit('Sorry,Please from entry!');

/**
 * 加载类 核心
 * 加载项目对象和框架文件
 * 用最少的代码做最不可能的事    @PGF
 * 创建时间: 2014-08-08 11:47  PGF  添加各个地方加载类和文件的方法
 * 修改时间：2014-08-10 18:29  PGF  修改了Model方法，返回加上clone
 * 修改时间：2015-02-28 18:32  PGF  发现了func每次调用都会重新引入，修改了错误
 */
class Loader
{

    /**
     * 存放实例之后的Loader对象
     */
    public static $load = false;
    private $core = array();
    private $model = array();
    private $module = array();
    private $database = false;
    private $template = false;
    private $controller = array();
    private $vendor = array();
    private $config = array();
    private $drive = array();
    private $function = array();
    private $Hooks = array();

    /**
     * 加载框架核心类
     * @param $name
     * @return empty
     */
    public static function core($name)
    {
        $load = self::init();
        if (isset($load->core[$name]))
            return;
        if ($file = $load->getPath($name, 'core')) {
            if ($load->load($file))
                $load->core[$name] = true;
        }
        return;
    }
    /**
     * 初始化Loader
     * @return Object
     */
    public static function init()
    {
        spl_autoload_register(__NAMESPACE__.'\Loader::autoload');
        if (!is_object(self::$load)) {
            self::$load = new Loader;
        }
        return self::$load;
    }

    /**
     * 加载钩子
     * @param $Hooks
     */
    public static function Hooks($Hooks){
        $load = self::init();
        $stop = strrpos($Hooks,'/');
        if(!isset($load->Hooks[$Hooks])){
            $file = $load->getPath($Hooks,'Hooks');
            if($stop==false){
                $className = $Hooks.'Hooks';

                $HooksClassName = '\Hooks\\'.str_replace('/','\\',$Hooks).'Hooks';
            }else{
                $className = substr($Hooks,$stop+1).'Hooks';
                $HooksClassName = '\Hooks\\'.str_replace('/','\\',substr($Hooks,$stop+1)).'Hooks';
            }
            if(!$load->load($file)){
                $file = __ROOT__ . parseDir(Config::config('core_dir'), 'Hooks').$className.'.php';
                if(!$load->load($file))
                    Debug::add('Loader:钩子文件 ' . $file . ' 不存在!');
                else
                    return $load->Hooks[$Hooks] = new $HooksClassName;
            }else{
                if(class_exists($HooksClassName))
                    return $load->Hooks[$Hooks] = new $HooksClassName;
                else
                    Debug::add('Loader:钩子 ' . $className . ' 不存在!');
            }
        }else
            return $load->Hooks[$Hooks];
    }

    /**
     * 加载控制器
     * @param $module
     * @param $controller
     * @param $method
     * @param bool $var
     * @param bool $run
     * @return bool
     */
    public static function controller($module, $controller, $method, $var = false ,$run = false)
    {
        $load = self::init();
        $cnm = $controller;
        $methodSuffix = Config::router('methodSuffix');
        $Class = $controller;
        $controller .= 'Controller';
        $file = $load->getPath($module.'/'.$controller, 'controller');
        $module_path = pathToUrl(dirname($file));
        if (isset($load->controller[$controller]) && is_object($load->controller[$controller])) {
            $load->controller[$controller]->module = $module;
            $load->controller[$controller]->method = $method;
            $load->controller[$controller]->controller = $Class;
            $load->control = $load->controller[$controller];
            if($run) {
                call_user_func_array(array($load->controller[ $controller ], $method . $methodSuffix), is_array($var) ? $var : array());
            }
            return $load->control;
        }else
        if ($load->load($file)) {
            $controllerName = 'Module\\'.$module.'\\'.$controller;
            if (class_exists($controllerName)) {
                $control = new $controllerName;
                $load->controller[$controller] = $control;
                if(method_exists($control, $method . $methodSuffix)) {
                    $control->method = $method;
                    $control->controller = $Class;
                    $control->module = $module;
                    $load->control = $load->controller[$controller];
                    if($run) {
                        call_user_func_array(array($control, $method . $methodSuffix), is_array($var) ? $var : array());
                    }
                }else{
                    Config::set(array(
                        'module_path'   => $module_path,
                    ),'runtime');
                    Debug::add('Loader:控制器方法 ' . $method . $methodSuffix . ' 没有定义,将直接调用模板文件.');
                    self::view($module.'/'.$cnm.'.'.$method);
                    return false;
                }
                return $load->control;
            }else{
                Config::set(array(
                    'module_path'   => $module_path,
                ),'runtime');
                Debug::add('Loader:控制器 ' . 'Module\\' . $module . '\\' . $controllerName . ' 不存在,将直接调用模板文件.');
                self::view($module.'/'.$cnm.'.'.$method);
                return false;
            }
        }else{
            Config::set(array(
                'module_path'   => $module_path,
            ),'runtime');
            Debug::add('Loader:控制器文件 ' . $file . ' 不存在,将直接调用模板文件!');
            self::view($module.'/'.$cnm.'.'.$method);
            return false;
        }
        return false;
    }

    /**
     * 加载数据模型
     * @param null $model
     * @return \Model\Model|\Model\$mmodel
     */
    public static function model($model = null)
    {
        $load = self::init();
        $table = $model;
        $load->core('Model');
        if ($model != null) {
            $model .= 'Model';
            //--如果load过此modal，直接返回
            $mmodel = 'Model\\'.$model;
            if (isset($load->model[$mmodel]) && is_object($load->model[$mmodel])) {
                return $load->model[$mmodel];
            }
            $file = $load->getPath($model, 'model');
            $load->load($file);
            if (class_exists($mmodel))    //--判断modal是否存在
                return $load->model[$mmodel] = new $mmodel;
            else {                       //--不存在，运行modal基类
                Debug::add('Loader:模型 ' . $model . ' 不存在,将会调入Model基类.');
                $load->model[$mmodel] = new Model($model);
                return $load->model[$mmodel];
            }
            return false;
        } else {
            return new Model();
        }
    }


    /**
     * 加载配置文件
     * @param $config
     * @return Array
     */
    public static function config($config)
    {
        $load = self::init();
        if (isset($load->config[$config]))
            return $load->$config[$config];
        $file = $load->getPath($config, 'config');
        return $load->config[$config] = $load->load($file);
    }

    /**
     * 加载插件类
     * @param $className
     * @param bool $config
     * @return Object
     */
    public static function vendor($className, $config = false)
    {
        $load = self::init();
        $class = $className;
        $className = 'Vendor\\'.str_replace('/','\\',$className);
        if (isset($load->vendor[$class])) {
            return new $className($config);
        } else {
            $file = $load->getPath($class, 'vendor');
            if (!$load->load($file)) {
                $file = __ROOT__ . $load->parseDir(Config::config('core_dir') , 'Vendor') . $class . '.class.php';
                if(file_exists($file)){
                    $load->load($file);
                }
            }

            if (class_exists($className)) {
                return $load->vendor[$class] = new $className($config);
            } else
                Debug::add('Loader:' . $className . ' not found.');
            return false;
        }
    }

    /**
     * 加载全局函数
     * @param $function
     * @return bool
     */
    public static function helper($function)
    {
        $load = self::init();
        if (isset($load->function[$function]))
            return true;
        $file = $load->getPath($function, 'helper');
        if (file_exists($file) && $load->load($file)) {
            $load->function[$function] = true;
            return true;
        } else {
            $d = __ROOT__ . $load->parseDir(Config::config('core_dir'), 'Helper') . $function . '.func.php';
            if(file_exists($d)){
                $load->function[$function] = true;
                return $load->load($d);
            }
            return false;
        }
    }

    /**
     * 加载框架驱动
     * @param $type
     * @param $drive
     * @return Object
     */
    public static function driver($type, $drive)
    {

        $load = self::init();
        if (!isset($load->drive[$type . $drive])) {
            $path = __ROOT__ . Config::config('core_dir') . '/System/drivers' . Config::config('drive_dir') . '/' . $type . '/' . $drive . '.class.php';
            if (file_exists($path)) {
                require($path);
                Debug::add($path, 1);
                return $load->drive[$type . $drive] = true;
            }
            Debug::add('Loader:驱动文件 ' . $path . ' 不存在.');

            return false;

        }

        return true;
    }

    /**
     * 加载视图
     * @param $view
     * @param bool $data
     * @param int $cacheTime
     * @param string $cacheKey
     * @return bool
     */
    public static function view($view, $data = false, $cacheTime = 0, $cacheKey = '')
    {
        $load = self::init();
        //-------向视图中添加变量
        $load->core('template');
        if (!$load->template) {
            $template = new template;
            $vars = Config::view_vars();
            $template->assign($vars);   //添加配置中的模板变量
            $load->template = $template;
        } else {
            $template = $load->template;
        }
        $template->assign($data);
        if(isset($load->control) && is_object($load->control))
            $template->assign('_ACT', array('controller'=>$load->control->controller,'method'=>$load->control->method));
        $template->display($view, $cacheTime, $cacheKey);
    }

    public static function template(){
        $load = self::init();
        //-------向视图中添加变量
        $load->core('template');
        if(!$load->template){
            $template = new template;
        }else{
            $template = $load->template;
        }
        $load->template = $template;
        return $template;
    }
    /**
     * 链接数据库
     * @return Object
     */
    public static function database()
    {
        $load = self::init();
        //判断是否连接过数据库
        if (!is_object($load->database)) {
            if (!class_exists('Db'))
                $load->core('Db');
            $drive = Config::database('driver');
            if ($load->driver('databases', $drive)) {
                $database = new $drive;
                if ($database->connect()) {
                    Debug::add('DB:数据库连接成功.');
                    return $load->database = $database;
                } else {
                    Debug::add('DB:数据库连接失败.');
                    exit;
                    return false;
                }

            } else {
                return false;
            }
        } else {
            return clone $load->database;
        }
    }

    //=====获取加载文件路径

    public static function load($file)
    {
        if (file_exists($file)) {
            $re = require($file);
            Debug::add($file, '1');
            return $re;
        }

        Debug::add('Loader:文件 ' . $file . ' 不存在.');

        return false;
    }

    //=====引用加载的文件

    private function getPath($name, $type)
    {
        if ($type == 'core')
            $d = $this->parseDir(Config::config('core_dir'), 'System' . DIRECTORY_SEPARATOR . 'bases' . DIRECTORY_SEPARATOR ) . $name . '.class.php';
        elseif ($type == 'controller')
            $d = $this->parseDir(Config::config('app_dir'), Config::config('Module_dir')) . $name . '.php';
        elseif ($type == 'model')
            $d = $this->parseDir(Config::config('app_dir'), Config::config('model_dir')) . $name . '.php';
        elseif ($type == 'vendor')
            $d = $this->parseDir(Config::config('app_dir') , Config::config('Vendor_dir')) . $name . '.class.php';
        elseif ($type == 'config')
            $d = $this->parseDir(Config::config('app_dir'), Config::config('config_dir')) . $name . '.php';
        elseif ($type == 'helper')
            $d = $this->parseDir(Config::config('app_dir'), Config::config('Helper_dir')) . $name . '.func.php';
        elseif ($type == 'view')
            $d = $this->parseDir(Config::config('app_dir'), Config::config('view_dir')) . $name . '.php';
//        elseif ($type == 'module')
//            $d = $this->parseDir(Config::config('app_dir'), Config::config('module_dir')) . $name . '.php';
        elseif ($type == 'Hooks'){
            $d = $this->parseDir(Config::config('app_dir'), Config::config('Hooks_dir')) . $name . 'Hooks.php';
        }
        return __ROOT__ . $d;
    }

    /**
     * 解析正确路径
     * @return String
     */
    private function parseDir()
    {
        $dirs = func_get_args();
        $dir = '';
        foreach ($dirs as $d) {
            $d = trim($d);
            if ($d[0] == DIRECTORY_SEPARATOR)
                $d = substr($d, 1, strlen($d) - 1);
            if ($d[strlen($d) - 1] != DIRECTORY_SEPARATOR)
                $d .= DIRECTORY_SEPARATOR;
            $dir .= $d;
        }
        return $dir;
    }

    /**
     * @param $classname
     * @return bool
     */
    public static function autoload($classname){
        $class=$classname;
        $classname = str_replace( '\\', DIRECTORY_SEPARATOR, $classname);
        $fg = explode(DIRECTORY_SEPARATOR, $classname);
        $status = false;
        if(!empty($fg)){
            $first = ucfirst(array_shift($fg));
            if($first == 'Model'){
                $m = implode($fg);
                $model = substr($m, 0, strlen($m)-5);
                $load = self::init();
                $load->core('Model');
                if ($model != null) {
                    $model .= 'Model';
                    //--如果load过此modal，直接返回
                    $mmodel = 'Model\\'.$model;

                    if (class_exists($mmodel))    //--判断modal是否存在
                        return TRUE;
                    $file = $load->getPath($model, 'model');
                    $load->load($file);
                    if (class_exists($mmodel))    //--判断modal是否存在
                        return TRUE;
                }
            }
            $autoload = Config::autoload();
            $p = implode(DIRECTORY_SEPARATOR, $fg);
            if(array_key_exists($first,$autoload)){
                if($first == 'Vendor')
                    $p .= '.class';
                if(is_array($autoload[$first])){
                    $wpath = $autoload[$first][0].$p.'.php';
                    foreach ($autoload[$first] as $key => $value) {
                        $path = $value . $p . '.php';
                        if(file_exists($path)!==false){
                            Debug::add($path,1);
                            $status = true;
                            require $path;
                            return;
                        }
                    }
                }else{
                    $wpath = $autoload[$first].$p.'.php';
                    $path = $autoload[$first] . $p . '.php';
                    if(file_exists($path)!==false){
                        $status = true;
                        Debug::add($path,1);
                        require $path;
                        return;
                    }
                }
            }
        }
        if(!class_exists($class)) {
            $status = false;
        }
        if($status==false)
        {
            if(isset($wpath)&&$wpath!=null){
                Debug::add($wpath . ' 不存在!');
                //输出第一个文件不存在,并结束
                exit($wpath.'不存在!');
            }
            return false;
        }
    }
}

//====================    END Loader.class.php      ========================//